#include "InPerUart.h"

#define DEF_TAG             "SerialCom"

#define DEF_SYNC_TIME_MINUTE           5

Com_s32 g_InPer_Uart_Ota_Total_Len = 0;
Com_u32 g_InPer_Uart_Ota_Package_Cnt = 0;
Com_u8 g_InPer_Uart_Ota_Failed = DEF_COM_FALSE;
Com_u8 g_InPer_Uart_Ota_Start_OK = DEF_COM_FALSE;
Com_u8 g_InPer_Uart_Get_Ver_Status = DEF_COM_FALSE;
SPerUartReadWaitInfo g_InPer_UartRead_Wait_Info[COMMAND_MAX_NUM];

Com_void Ext_InPer_Uart_Set_Ota_Total_Len(Com_s32 len)
{
    g_InPer_Uart_Ota_Total_Len = len;
}

Com_u8 Ext_InPer_Uart_Get_Ota_Flag(void)
{
    return g_InPer_Uart_Ota_Start_OK;
}

Com_u8 Ext_InPer_Uart_CheckSum(Com_pu8 recv_buf,Com_u32 len)
{
    Com_s32 j;
    Com_u32 datalen = 0,datasum = 0;
    Com_u8 checksum;

    datalen = len + DEF_HEAD_LENGTH;

    /* check code */
    for (j = 0;j < datalen; j++)
    {
        datasum += recv_buf[j];
    }

    checksum = datasum % 256;

    return checksum;
}

Com_pvoid InPer_Uart_Check_Mcu_Version(Com_pvoid arg)
{
    int cnt = 0;

    sleep(5);
    while(DEF_COM_TRUE)
    {
        if(g_InPer_Uart_Get_Ver_Status == DEF_COM_TRUE)
        {
            PRT_INFO(DEF_TAG,"check mcu version success\n");
            break;
        }

        if(cnt >= 6)
        {
            PRT_WARN(DEF_TAG,"timeout of check mcu version\n");
            break;
        }

        Ext_InPer_UartSend_Version();
        cnt++;
        sleep(3);
    }

    /* upgrade complete get mcu version */
    Ext_InComFile_JudgeRemove(DEF_FLAG_MCU_NEED_UPGRADE);
    pthread_exit(0);
}

Com_void InPer_Uart_Check_Recv_Status(Com_void)
{
    Com_s32 ret = 0;

    if(g_InPer_UartRead_Wait_Info[COMMAND_CHECK_VERSION].again == DEF_COM_TRUE)
    {
        g_InPer_UartRead_Wait_Info[COMMAND_CHECK_VERSION].again = DEF_COM_FALSE;
        Ext_InPer_UartSend_Version();
    }

    if(g_InPer_UartRead_Wait_Info[COMMAND_TRANSFER_UPGRADE_PACKAGE].again == DEF_COM_TRUE)
    {
        static Com_s32 cnt = 0;
        g_InPer_UartRead_Wait_Info[COMMAND_TRANSFER_UPGRADE_PACKAGE].again = DEF_COM_FALSE;

        if(cnt >= 100)
        {
            Ext_InComFile_JudgeRemove(DEF_FLAG_MCU_NEED_UPGRADE);
            cnt = 0;
            return;
        }

        if(g_InPer_Uart_Ota_Failed == DEF_COM_FALSE)
        {
            if(g_InPer_Uart_Ota_Package_Cnt > 0)
            {
                if(g_InPer_Uart_Ota_Package_Cnt == 1)
                {
                    g_InPer_Uart_Ota_Package_Cnt = 0;
                }
                else
                {
                    g_InPer_Uart_Ota_Package_Cnt -= 2;
                }
            }
            g_InPer_Uart_Ota_Failed = DEF_COM_TRUE;
        }

send_again:
        usleep(DEF_PER_UART_READ_MS * 2 * 1000);
        PRT_INFO(DEF_TAG,"transfer upgrade again\n");
        ret = Ext_InPer_UartSend_Ota_Package(g_InPer_Uart_Ota_Package_Cnt);
        if(ret < 0)
        {
            goto send_again;
        }

        cnt++;
    }

    if(g_InPer_UartRead_Wait_Info[COMMAND_MCU_REPORT_INIT_STATUS].again == DEF_COM_TRUE)
    {
        g_InPer_UartRead_Wait_Info[COMMAND_MCU_REPORT_INIT_STATUS].again = DEF_COM_FALSE;
        Ext_InPer_UartSend_Report_Init_Status();
    }
}

Com_pvoid InPer_Uart_Thread(Com_pvoid arg)
{
    Com_s32 ret;
    Com_s32 serial_fd;
    Com_u32 ota_total_num = 0;
    Com_u8 powerup_sync_time = DEF_COM_FALSE;
    Com_u8 powerup_get_mcu_ver = DEF_COM_FALSE;
    Com_u8 powerup_get_init_status = DEF_COM_FALSE;
    Com_u8 recv_buff[DEF_PER_UART_BUF_SIZE];
    StComSecondTimer sync_mcu_timer;
    StComSecondTimer uart_error_timer;

    memset(&sync_mcu_timer,0,sizeof(sync_mcu_timer));
    memset(&uart_error_timer,0,sizeof(uart_error_timer));
    memset(&g_InPer_UartRead_Wait_Info,0,sizeof(g_InPer_UartRead_Wait_Info));

    ret = Ext_InPer_Uart_Opt_Init();
    if (ret == -1)
    {
        printf("Error: Uart Opt Init failed!\n");
        return NULL;
    }

    Ext_InPer_UartRead_Head_Flag(DEF_COM_FALSE);
    Ext_InPer_UartRead_Set_Len(0);
    serial_fd = Ext_InPer_Uart_Fd();
    Ext_InComTimer_GetSec(DEF_COM_SET_NEW_TIME,&sync_mcu_timer);
    Ext_InComTimer_GetSec(DEF_COM_SET_NEW_TIME,&uart_error_timer);

    DEF_COM_SET_THREAD_NAME("Serial_Com",g_ComThread_Num);

    while(g_ComThread_Running)
    {
        if(Ext_InComTimer_GetSec(DEF_COM_NOT_SET_TIME,&uart_error_timer) >= (10 * 60))
        {
        }

        memset(recv_buff,0,sizeof(recv_buff));

        ret = Ext_InPer_UartRead_Process(recv_buff,serial_fd);
        if ((ret >= 4) && (ret <= DEF_PER_UART_BUF_SIZE))
        {
            Ext_InComTimer_GetSec(DEF_COM_SET_NEW_TIME,&uart_error_timer);

            Com_u32 d_len = (recv_buff[4] << 8) + recv_buff[5];
            Com_u8 mcusum = recv_buff[ret - 1];
            Com_u8 linuxsum = 0;

            linuxsum = Ext_InPer_Uart_CheckSum(recv_buff,d_len);
            if(linuxsum != mcusum)
            {
                PRT_WARN(DEF_TAG,"check code error !\n");
                PRT_INFO(DEF_TAG,"mcusum[0x%02x] != linuxsum[0x%02x] \n",mcusum,linuxsum);
                continue;
            }

            int command = recv_buff[3];
            PRT_INFO(DEF_TAG,"recv cmd: 0x%02x,len: %d\n",command,d_len);

            g_InPer_UartRead_Wait_Info[command].cnt = 0;
            g_InPer_UartRead_Wait_Info[command].flag = DEF_COM_TRUE;
            g_InPer_UartRead_Wait_Info[command].again = DEF_COM_FALSE;
            switch(command)
            {
            case COMMAND_MANUAL_FEED :
            {
            }
                break;

            case COMMAND_MCU_GET_TIME :
            {
                Ext_InPer_UartSend_Get_Time();
            }
                break;

            case COMMAND_SET_MCU_TIME :
            {
            }
                break;

            case COMMAND_FEED_REMIND :
            {
                Ext_InPer_UartHandle_Remind(recv_buff);
            }
                break;

            case COMMAND_FEED_RESULT :
            {
                Ext_InPer_UartHandle_Feed_Result(recv_buff);
            }
                break;

            case COMMAND_CHECK_VERSION :
            {
                g_InPer_Uart_Get_Ver_Status = DEF_COM_TRUE;
                Ext_InPer_UartHandle_Version(recv_buff);
            }
                break;

            case COMMAND_DEVIVE_RESET :
            {
            }
                break;

            case COMMAND_START_UPGRADE :
            {
                PRT_NORMAL("start upgrade now\n");
                g_InPer_Uart_Get_Ver_Status = DEF_COM_FALSE;
                g_InPer_Uart_Ota_Start_OK = DEF_COM_TRUE;

                if ((g_InPer_Uart_Ota_Total_Len % 256) == 0)
                {
                    ota_total_num = g_InPer_Uart_Ota_Total_Len / 256 + 1;
                }
                else
                {
                    ota_total_num = g_InPer_Uart_Ota_Total_Len / 256 + 2;
                }

                g_InPer_Uart_Ota_Package_Cnt = 0;
                Ext_InPer_UartSend_Ota_Package(g_InPer_Uart_Ota_Package_Cnt);
                g_InPer_Uart_Ota_Package_Cnt++;
            }
                break;

            case COMMAND_TRANSFER_UPGRADE_PACKAGE :
            {
                Com_s32 up_ret = -1;
                g_InPer_Uart_Ota_Failed = DEF_COM_FALSE;

                if(g_InPer_Uart_Ota_Package_Cnt >= ota_total_num)
                {
                    PRT_NORMAL("end of transfer upgrade package\n");
                    pthread_t check_id;
                    pthread_create(&check_id, NULL, InPer_Uart_Check_Mcu_Version, NULL);
                    pthread_detach(check_id);
                    continue;
                }
send_again:
                PRT_NORMAL("transfer upgrade now\n");
                up_ret = Ext_InPer_UartSend_Ota_Package(g_InPer_Uart_Ota_Package_Cnt);
                if(up_ret < 0)
                {
                    goto send_again;
                }
                g_InPer_Uart_Ota_Package_Cnt++;
            }
                break;

            case COMMAND_MCU_NOTICE_RESET :
            {
                Ext_InPer_UartHandle_Reset();
            }
                break;

            case COMMAND_LED_ONOFF :
            {
            }
                break;

            case COMMAND_MCU_NOTICE_FEED :
            {
            }
                break;

            case COMMAND_HEARTBEAT :
            {
                Ext_InPer_UartSend_Heartbeat();
            }
                break;

            case COMMAND_SEND_DEV_NET_STATUS :
            {
            }
                break;

            case COMMAND_MCU_REPORT_INIT_STATUS:
            {
            }
                break;

            case COMMAND_SET_MCU_FUNCTION_SW :
            {
                Ext_InPer_UartHandle_Bool_SW(recv_buff);
            }
                break;

            default:
                PRT_WARN(DEF_TAG,"no this cmd: %02x\n",command);
                break;
            }
        }
        else if (ret == 0) /* read timeout */
        {
            InPer_Uart_Check_Recv_Status();

            if (powerup_get_mcu_ver == DEF_COM_FALSE)
            {
                PRT_INFO(DEF_TAG,"check mcu version\n");
                Ext_InPer_UartSend_Version();
                powerup_get_mcu_ver = DEF_COM_TRUE;
            }

            /* sync mcu time */
            if(Ext_InComFile_Access(DEF_FLAG_SYNC_TIME_OK) == DEF_COM_FILE_EXIST)
            {
                /* 5 min sync time */
                if(powerup_sync_time == DEF_COM_FALSE)
                {
                    PRT_INFO(DEF_TAG,"sync mcu time\n");
                    Ext_InPer_UartSend_Set_Time();
                    powerup_sync_time = DEF_COM_TRUE;
                }
                else if(powerup_get_init_status == DEF_COM_FALSE)
                {
                    PRT_NORMAL("get all init status\n");
                    Ext_InPer_UartSend_Report_Init_Status();
                    powerup_get_init_status = DEF_COM_TRUE;
                }
                else if(Ext_InComTimer_GetSec(DEF_COM_NOT_SET_TIME,&sync_mcu_timer) >= (DEF_SYNC_TIME_MINUTE * 60))
                {
                    Ext_InPer_UartSend_Set_Time();
                    Ext_InComTimer_GetSec(DEF_COM_SET_NEW_TIME,&sync_mcu_timer);
                }
            }
        }
    }

    Ext_InPer_Uart_Close();
    DEF_COM_EXIT_THREAD(g_ComThread_Num);
}


Com_void Ext_InPer_Uart_Init(Com_void)
{
    pthread_t id;

    pthread_create(&id, NULL,InPer_Uart_Thread, NULL);
    pthread_detach(id);
}
